﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace mirror
{
    public class Shadow
    {
        Effect mFx;
        VertexBuffer mVB;
        IndexBuffer mIB;
        VertexDeclaration mVertDecl;
        Texture2D mFlare;

        public static int MAX_QUADS = 400;
        Vector4[] mPos;
        int mObjectNum;

        public void Initialize()
        {
            VertexElement[] vert_elems = {
            new VertexElement(0, VertexElementFormat.Vector4,
                                    VertexElementUsage.Position, 0)};
            mVertDecl = new VertexDeclaration(vert_elems);

            mObjectNum = 0;
            mPos = new Vector4[MAX_QUADS*4];
            mFx = cRenderManager.Instance.Content().Load<Effect>("Shadow");
            mFlare = cRenderManager.Instance.Content().Load<Texture2D>("particles/flare");
            mVB = new VertexBuffer(cRenderManager.Instance.Device(), mVertDecl, MAX_QUADS * 16 * 4, BufferUsage.WriteOnly);
            mIB = new IndexBuffer(cRenderManager.Instance.Device(),IndexElementSize.SixteenBits, MAX_QUADS * 4 * 6, 0);

            short[] indices = new short[MAX_QUADS * 6];
            for (int i = 0; i < MAX_QUADS; ++i)
            {
                short i4 = (short)(i * 4);
                int i6 = i * 6;
                indices[i6 + 0] = i4;
                indices[i6 + 1] = (short)(i4 + 1);
                indices[i6 + 2] = (short)(i4 + 2);
                indices[i6 + 3] = (short)(i4 + 2);
                indices[i6 + 4] = (short)(i4 + 3);
                indices[i6 + 5] = i4;
            }
            
            mIB.SetData(indices);
            

            mFx.Parameters["level_ll"].SetValue(new Vector2(-50,-50));
            mFx.Parameters["level_dims"].SetValue(new Vector2(100,100));
            mFx.Parameters["Texture"].SetValue(mFlare);
        }

        public void SetPositions(int objIndex, Vector3 pos, bool isPlayer)
        {
            if (objIndex >= MAX_QUADS)
                return;
            float s = isPlayer ? 4.0f : 1.5f;
            uint i4 = (uint)objIndex * 4;
            mPos[i4 + 0] = new Vector4(pos.X-s, pos.Y, pos.Z-s, 0);
            mPos[i4 + 1] = new Vector4(pos.X-s, pos.Y, pos.Z+s, 1);
            mPos[i4 + 2] = new Vector4(pos.X+s, pos.Y, pos.Z+s, 2);
            mPos[i4 + 3] = new Vector4(pos.X+s, pos.Y, pos.Z-s, 3);
        }

        public void SetObjNum(int num)
        {
            mObjectNum = num;
        }

        public void Render()
        {
            PixHelper.BeginEvent(0xFFFFFFFF,"Rendering to shadow");

            GraphicsDevice device = cRenderManager.Instance.Device();
            if (mObjectNum == 0)
                return;

            mFx.Parameters["View"].SetValue(Camera.Instance.ViewMatrix);
            mFx.Parameters["Projection"].SetValue(Camera.Instance.ProjectionMatrix);

            device.BlendState.AlphaBlendFunction = BlendFunction.Add;
            device.BlendState.ColorSourceBlend = Blend.One;
            device.BlendState.ColorDestinationBlend = Blend.InverseSourceAlpha;
            device.BlendState.AlphaSourceBlend = Blend.One;
            device.BlendState.AlphaDestinationBlend = Blend.InverseSourceAlpha;
            device.DepthStencilState.DepthBufferWriteEnable = false;
            device.RasterizerState.CullMode = CullMode.CullClockwiseFace;

            int elems = mObjectNum*4;
            mVB.SetData(mPos, 0, elems );
            device.SetVertexBuffer(mVB);
            device.Indices = mIB;
            
            foreach (EffectPass pass in mFx.CurrentTechnique.Passes)
            {
                pass.Apply();
                device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, elems, 0, elems / 2);
            }

            device.SetVertexBuffer(null);

            PixHelper.EndEvent();

            device.BlendState.AlphaBlendFunction = BlendFunction.Add;
            device.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace;
        }
    }
}
